#region  == Copyright == 
// =====================================================================
//  Microsoft Consulting Services France - Aymeric Mouillé - 2013
//  Projet     : CRM Solution Management Tool
//  Fichier    : JobProgressControl.cs (30/04/2013 16:50)
//  
//  Copyright (C) Microsoft Corporation.  All rights reserved.
// =====================================================================
#endregion

namespace CRM.Solution.Management.Tool.Controls
{
    #region  == Using == 
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Threading;
    using System.Windows.Forms;

    using CRM.Solution.Manager.Properties;

    using Microsoft.Xrm.Sdk;
    using Microsoft.Xrm.Sdk.Query;

    #endregion

    /// <summary>
    /// </summary>
    public partial class JobProgressControl : UserControl
    {
        /// <summary>
        /// </summary>
        private readonly BackgroundWorker BgWorkerCurrentJob;

        /// <summary>
        /// </summary>
        private readonly BackgroundWorker BgWorkerCurrentJobProgress;

        /// <summary>
        /// </summary>
        private JobItem CurrentJob;

        #region Main Form
        /// <summary>
        /// Gets the main form.
        /// </summary>
        /// <value>
        /// The main form.
        /// </value>
        private MainForm MainForm
        {
            get
            {
                return (MainForm)Parent.Parent.Parent;
            }
        }
        #endregion

        #region = Constructor =
        /// <summary>
        /// Initializes a new instance of the <see cref="JobProgressControl" /> class.
        /// </summary>
        public JobProgressControl()
        {
            InitializeComponent();

            BgWorkerCurrentJob = new BackgroundWorker();
            BgWorkerCurrentJobProgress = new BackgroundWorker();

            progressBarJob.Minimum = 0;
            progressBarJob.Maximum = 100;
        }
        #endregion

        #region Load Control
        /// <summary>
        /// Loads the control.
        /// </summary>
        public void LoadControl()
        {
            BgWorkerCurrentJob.DoWork += bgWorkerCurrentJob_DoWork;
            BgWorkerCurrentJob.RunWorkerCompleted += bgWorkerCurrentJob_RunWorkerCompleted;
            if (!BgWorkerCurrentJob.IsBusy)
            {
                MainForm.UpdateStripStatus("Loading, please wait ...");
                BgWorkerCurrentJob.RunWorkerAsync();
            }
        }
        #endregion

        #region Get Progress
        /// <summary>
        /// Gets the progress.
        /// </summary>
        /// <param name="importId">The import id.</param>
        private void GetProgress(Guid importId)
        {
            try
            {
                IOrganizationService service = MainForm.GetOrganizationService();
                var job = service.Retrieve("importjob", importId, new ColumnSet(true));
                decimal progress = Convert.ToDecimal(job["progress"]);

                if (job.Attributes.Contains("data"))
                {
                    CurrentJob.LogData = job["data"].ToString();
                    CurrentJob.Status = SolutionHelper.GetImportLogStatus(CurrentJob.LogData);
                }
                if (job.Attributes.Contains("completedon"))
                {
                    CurrentJob.CompletedOn = job["completedon"].ToString();
                    CurrentJob.IsCompleted = true;
                }
                CurrentJob.Progress = progress;
                if (CurrentJob.IsCompleted)
                {
                    return;
                }
            }
            catch (Exception)
            {
                // Ignore
            }

            Thread.Sleep(Settings.Default.CheckInterval);
        }
        #endregion

        #region Convert Job Item From Import Job
        /// <summary>
        /// Converts the job item from import job.
        /// </summary>
        /// <param name="importJob">The import job.</param>
        /// <returns></returns>
        private JobItem ConvertJobItemFromImportJob(Entity importJob)
        {
            var jobItem = new JobItem { JobId = importJob.Id, Name = importJob["name"].ToString(), SolutionName = importJob["solutionname"].ToString(), CreatedOn = importJob["startedon"].ToString(), };

            if (importJob.Attributes.Contains("progress"))
            {
                jobItem.Progress = Convert.ToDecimal(importJob["progress"]);
            }

            if (importJob.Attributes.Contains("data"))
            {
                jobItem.Status = SolutionHelper.GetImportLogStatus(importJob["data"].ToString());
            }
            return jobItem;
        }
        #endregion

        #region Load Current Import Job
        /// <summary>
        /// Loads the current import job.
        /// </summary>
        private void LoadCurrentImportJob()
        {
            MainForm.UpdateStripStatus("Querying for import job ...");
            CurrentJob = null;

            try
            {
                if (MainForm.CurrentSolutionImportJobId != Guid.Empty)
                {
                    Entity importJob = MainForm.OrganizationService.Retrieve("importjob", MainForm.CurrentSolutionImportJobId, new ColumnSet(true));
                    MainForm.UpdateStripStatus("Processing results ...");
                    CurrentJob = ConvertJobItemFromImportJob(importJob);
                }
                else
                {
                    FilterExpression filter = new FilterExpression();
                    filter.AddCondition(new ConditionExpression("completedon", ConditionOperator.Null));
                    var query = new QueryExpression("importjob") { ColumnSet = new ColumnSet(true), Criteria = filter };

                    List<JobItem> jobItems = new List<JobItem>();
                    var response = MainForm.OrganizationService.RetrieveMultiple(query);
                    MainForm.UpdateStripStatus("Processing results ...");
                    foreach (var importJob in response.Entities)
                    {
                        jobItems.Add(ConvertJobItemFromImportJob(importJob));
                    }
                    CurrentJob = jobItems.FirstOrDefault();
                }
            }
            catch (Exception ex)
            {
                MainForm.UpdateStripStatus(string.Format("Failed to retrieve results! ({0})", ex.Message));
                if (MessageBox.Show(ex.Message, "Error", MessageBoxButtons.RetryCancel, MessageBoxIcon.Error) == DialogResult.Retry)
                {
                    LoadCurrentImportJob();
                }
            }
        }
        #endregion

        #region Bg Worker Current Job Progress Do Work
        /// <summary>
        /// Handles the DoWork event of the bgWorkerCurrentJobProgress control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">
        /// The <see cref="System.ComponentModel.DoWorkEventArgs" /> instance containing the event data.
        /// </param>
        private void bgWorkerCurrentJobProgress_DoWork(object sender, DoWorkEventArgs e)
        {
            GetProgress(CurrentJob.JobId);
        }
        #endregion

        #region Bg Worker Current Job Progress Run Worker Completed
        /// <summary>
        /// Handles the RunWorkerCompleted event of the bgWorkerCurrentJobProgress control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">
        /// The <see cref="System.ComponentModel.RunWorkerCompletedEventArgs" /> instance containing the event data.
        /// </param>
        private void bgWorkerCurrentJobProgress_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (CurrentJob == null)
            {
                return;
            }
            groupBoxProgress.Visible = true;
            progressBarJob.Value = (int)CurrentJob.Progress;
            lblImportProgress.Text = string.Format("{0}%", CurrentJob.Progress.ToString("0.00"));
            lblImportStatus.Text = CurrentJob.Status;
            propertyGridJob.SelectedObject = CurrentJob;

            if (CurrentJob.IsCompleted)
            {
                MainForm.UpdateStripStatus("Solution imported!", progressBarJob.Value);
            }
            else
            {
                MainForm.UpdateStripStatus("Importing solution ...", progressBarJob.Value);

                if (!BgWorkerCurrentJobProgress.IsBusy)
                {
                    BgWorkerCurrentJobProgress.RunWorkerAsync();
                }
            }
            Application.DoEvents();
        }
        #endregion

        #region Bg Worker Current Job Do Work
        /// <summary>
        /// Handles the DoWork event of the bgWorkerCurrentJob control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">
        /// The <see cref="System.ComponentModel.DoWorkEventArgs" /> instance containing the event data.
        /// </param>
        private void bgWorkerCurrentJob_DoWork(object sender, DoWorkEventArgs e)
        {
            LoadCurrentImportJob();
        }
        #endregion

        #region Bg Worker Current Job Run Worker Completed
        /// <summary>
        /// Handles the RunWorkerCompleted event of the bgWorkerCurrentJob control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">
        /// The <see cref="System.ComponentModel.RunWorkerCompletedEventArgs" /> instance containing the event data.
        /// </param>
        private void bgWorkerCurrentJob_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (CurrentJob == null)
            {
                MainForm.UpdateStripStatus("Job not found !", 100);
                MainForm.CanTryAgain(true);
                return;
            }

            MainForm.UpdateStripStatus("Job found!", 100);
            MainForm.CanTryAgain(false);
            propertyGridJob.SelectedObject = CurrentJob;
            BgWorkerCurrentJobProgress.DoWork += bgWorkerCurrentJobProgress_DoWork;
            BgWorkerCurrentJobProgress.RunWorkerCompleted += bgWorkerCurrentJobProgress_RunWorkerCompleted;
            if (!BgWorkerCurrentJobProgress.IsBusy)
            {
                BgWorkerCurrentJobProgress.RunWorkerAsync();
            }
        }
        #endregion
    }
}
